package com.xiao.code.parse;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSON;

import japa.parser.ast.ImportDeclaration;
import japa.parser.ast.PackageDeclaration;
import japa.parser.ast.expr.NameExpr;

/**
 * java映射容器
 * @author Administrator
 *
 */
public class JavaMap {
	public static final Map<String,JavaDescribe> javaAllMap = new HashMap<>();
	

	Map<String,JavaDescribe> javaMap = new HashMap<>();
	
	Map<String,JavaDescribe> slipMap = new HashMap<>();

	
	Set<String> poolPackageSet = new HashSet<>(); 
	
	public void load(List<PoolDes> list , boolean lib){
	  for (PoolDes pool : list){
		  
		  File proPath = new File(pool.poolPath);

		  for (File m : proPath.listFiles()){
			  if(!m.isDirectory() || !m.getName().contains("-")){
				  continue;
			  }
			  
			  System.out.println("load:" + pool.poolName + "-----" + pool.poolPath + "-------" + m.getName());
			  
			 String mName =  m.getName();
			 
			 if (lib){
				 if (!mName.contains("model") && !mName.contains("client")){
					 continue;
				 }
			 }
			 
			 
			 loadJavaFile(mName, pool, new File(m.getPath() + "/src/main/java"));
			  
		  };
		  
	  }
		
	}
	
	/**
	 * 加载java文件
	 * @param mName
	 * @param pool
	 * @param file
	 */
	public void loadJavaFile(String mName , PoolDes pool , File file ){
		if (file.isDirectory()){
			
			for (File f : file.listFiles()){
				loadJavaFile(mName, pool, f);
			}
		}
		
		if (!file.getName().endsWith(".java")){
			return ;
		}
		
		System.out.println("load:" + file.getPath());
		
		JavaDescribe javaDescribe = new JavaDescribe();
		javaDescribe.file = file;
		String paName = file.getParent();
		paName = paName.substring(file.getPath().indexOf(""+File.separator+"src"+File.separator+"main"+File.separator+"java") + (""+File.separator+"src"+File.separator+"main"+File.separator+"java").length() + 1, paName.length());
		paName = paName.replace(File.separator, ".");
		javaDescribe.packgeName = paName;
   	    
		String pNames[] = paName.split("\\.");

        if(paName.startsWith("com.odianyun.basics.") || paName.startsWith("com.odianyun.back.")){
        	 javaDescribe.poolName = pNames[3];
             poolPackageSet.add(StringUtils.join(Arrays.asList(pNames).subList(0, 4), "."));

		}else if (pNames.length > 2)  {
			
       	     javaDescribe.poolName = pNames[2];
		}
        javaDescribe.modelName = mName;
        
        String key = javaDescribe.packgeName + "." + file.getName().split("\\.")[0];
        
        javaDescribe.key = key;
        javaDescribe.claName = file.getName().split("\\.")[0];
        
        try {
        	 javaDescribe.getJavaParser();
        	 javaMap.put(key, javaDescribe);
             javaAllMap.put(key, javaDescribe);
             
		} catch (Exception e) {
			slipMap.put(key, javaDescribe);
			e.printStackTrace();
			System.out.println("initError:" + file.getPath());
		}
       
       
	}
	
	/**
	 * 寻找相关包
	 * @param packageName
	 * @return
	 */
	public List<String> findJava(String packageName){
		
		Set<String> keySet = javaAllMap.keySet();
		return keySet.stream().filter(key -> {
			if (packageName.endsWith("*") && key.startsWith(packageName.replace(".*", ""))){
				return true;
			}else if(key.equals(packageName)){
				return true;
			}else {
				return false;
			}
		}).collect(Collectors.toList());
		
	}
	
	/**
	 * 初始化
	 * @throws Exception
	 */
	public void loadEndInit() throws Exception{
		
	   List<String> notFind = new ArrayList<>();
		
		Set<String> keySet = javaMap.keySet();
		for (String key : keySet){
			JavaDescribe java = javaMap.get(key);
			
			try {
				List<ImportDeclaration> importList =  java.getJavaParser().getImports();
				List<ImportDeclaration> importNewList = new ArrayList<>();
				if (importList == null){
					continue;
				}
				
				for (ImportDeclaration i : importList){
					if (i.toString().contains(".*;")){
						String imI = i.getName()  + ".*";
						if(!Start.clientMap.checkMovePool(imI)){
							importNewList.add(i);
							continue;
						}
						
						List<String> javaKeyList = findJava(imI);
						if (javaKeyList == null || javaKeyList.isEmpty()){
							notFind.add(imI.toString());
						}else {
							Set<String> javaFList = java.findAllImplJava();
							
							javaKeyList.stream().filter(e -> {
								String claName = e.substring(e.lastIndexOf(".") + 1 , e.length());
								return javaFList.contains(claName);
							})
							.forEach(e -> importNewList.add(new ImportDeclaration(new NameExpr(e),false,false)));
						}
						
					}else {
						importNewList.add(i);
					}
				}
				
				java.getJavaParser().setImports(importNewList);

			} catch (Exception e) {
				System.out.println(java.packgeName);
				System.out.println("java.file.getPathERROR():" + java.file.getPath() + " java.packgeName:" + java.packgeName);
				e.printStackTrace();
			}
		}
		
		if (!notFind.isEmpty()){
			throw new RuntimeException("not find " + JSON.toJSONString(notFind));
		}
		
	}

	public void  tetest(Consumer<Object> action){

	}
	
	/**
	 * 保存
	 * @param path
	 * @throws Exception 
	 */
	public void doSave(String path) throws Exception{
		System.out.println("doSave:" + path);


		Set<String> keySet = javaMap.keySet();
		
		ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
		
		
		keySet.stream().parallel().forEach(key -> {
			try {
				System.out.println("doSave:" + key);
				String body = null;
				try {
					FutureTask<String> task = new FutureTask<>(new Callable<String>() {

						@Override
						public String call() throws Exception {
							return javaMap.get(key).getJavaParser().toString();
						}
					});
					
					pool.execute(task );
					
					body = task.get(30, TimeUnit.SECONDS);
				} catch (Exception e) {
					body = FileUtils.readFileToString(javaMap.get(key).file);
				}
				String fPath = path + File.separator + javaMap.get(key).modelName +  File.separator +  "src"+File.separator+"main"+File.separator+"java" + File.separator + key.replace(".", File.separator) + ".java";
				FileUtils.writeStringToFile(new File(fPath), body.replace(Start.rpStr + ";", ""));
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
		
	
	}
	
	/**
	 * 
	 * 寻找类
	 * @param simpleClassName
	 * @return
	 */
	public String findClass(String simpleClassName){
		
		return javaMap.keySet().stream().filter(e -> e.endsWith("." + simpleClassName))
		                         .collect(Collectors.toList())
		                         .get(0);
		
	}
	
	
	/**
	 * 修改包名
	 * @param java
	 * @param nPackageName
	 */
	public void rnamePackage(JavaDescribe java , String nPackageName){
		
		
		String impl = java.getJavaParser().getPackage().getName() + "." + java.claName;
		String newImpl = nPackageName + "." + java.claName;
		
		if(newImpl.contains("com.odianyun.odss.soa.dto.odss.soa.dto.basics.merchant.model.dto")){
			
			System.out.println(newImpl);
			
		}
		
		// 如果修改过直接返回
		if(impl.equals(newImpl)){
			return ;
		}
		
		// 设置为新的包
		java.getJavaParser().setPackage(new PackageDeclaration(new NameExpr(nPackageName)));
		
		// 替换掉所有引用
	    javaAllMap.keySet().stream().forEach( key -> javaAllMap.get(key).rpImp(impl,newImpl));
	    
	    // 如果之前有key 删除掉key
		if(javaMap.containsKey(java.key)){
			javaMap.remove(java.key);
		}
		
		// 更换为新key
		javaMap.put(newImpl, java);
		javaAllMap.put(newImpl, java);

		java.key = newImpl;
		java.packgeName = nPackageName;
		
	}
	
	
	/**
	 * 如果是需要迁移的pool
	 * @param className
	 * @return
	 */
	public  boolean checkMovePool(String className){
		return poolPackageSet.stream()
				 .filter(is -> className.startsWith(is)).count() > 0;
	}

}
